package eom.example.elasticsearch.utils;

import bom.example.common.utils.MapUtils;
import bom.example.common.utils.ReflectUtils;
import com.alibaba.fastjson.JSON;
import io.searchbox.client.http.JestHttpClient;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author X.I.O
 * @title: ElasticSearchUtils
 * @projectName springboot
 * @description: TODO
 * @date 2021/11/2 11:48
 */
@Component
public class ElasticSearchUtils {

    private final static String ID="id";

    @Autowired
    @Qualifier("restHighLevelClient")
    private RestHighLevelClient client;



    /**
     * 创建索引
     * @param indexName
     * @throws IOException
     */
    public  void createIndex(String indexName) throws IOException {
        //1. 创建索引
        CreateIndexRequest index = new CreateIndexRequest(indexName);
        //2. 客户端执行请求,请求后获得相应
        CreateIndexResponse response = client.indices().create(index, RequestOptions.DEFAULT);
        //3.打印结果
        System.out.println(response.toString()+"这是结果");
    }


    /**
     * 判断索引是否存在
     * @param indexName
     * @return
     * @throws IOException
     */
    public boolean exitIndex(String indexName) throws IOException{
        GetIndexRequest request = new GetIndexRequest(indexName);
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        return exists;
    }

    /**
     * 通过索引的id获取单个数据对象
     * @param indexName 索引
     * @param idValue  id值
     * @param cls    反射类
     * @param <T>   反射泛型
     * @return  单个数对象
     * @throws IOException
     */
    public <T> T getDocumentById(String indexName,String idValue,Class<T> cls) throws IOException {
        GetRequest request = new GetRequest(indexName, idValue);
        GetResponse response = client.get(request, RequestOptions.DEFAULT);
        Map<String, Object> map=response.getSource();
        T t =MapUtils.getObject(map,cls);
        return t;
    }

    /**
     * 判断创建的索引是否存在
     * @param indexName 索引名称
     * @return 是否存在
     * @throws Exception
     */
    public boolean existIndexName(String indexName,String idValue) throws Exception{
        GetRequest request = new GetRequest(indexName, idValue);
        //不获取返回的_source 的上下文
        request.fetchSourceContext(new FetchSourceContext(false));
        request.storedFields("_none");
        boolean exists = client.exists(request, RequestOptions.DEFAULT);
        return  exists;
    }


    /**
     * 通过id更新文档数据
     * @param t
     * @param indexName
     * @param <T>
     * @throws Exception
     */
    public <T> void updateDocumentById(T t,String indexName) throws Exception{
        Object val=ReflectUtils.getObjectByFeild(t,ID);
        if(val==null){
            return;
        }
        String id=String.valueOf(val);
        UpdateRequest request = new UpdateRequest(indexName, id);
        request.timeout("1s");
        request.doc(JSON.toJSONString(t),XContentType.JSON);
        UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
        System.out.println(response.status());

    }


    /**
     * 添加单个索引数据
     * @param t 对象
     * @param indexName 索引名称
     * @param <T> 数据泛型
     * @throws Exception
     */
    public <T> void addDocument(T t,String indexName) throws Exception{
        Object val=ReflectUtils.getObjectByFeild(t,ID);
        if(val==null){
            throw new Exception("id不得为空");
        }
        String id=String.valueOf(val);
        //创建请求
        IndexRequest request = new IndexRequest(indexName);
        //规则
        request.id(id).timeout(TimeValue.timeValueSeconds(1));
        //将数据放到请求中
        request.source(JSON.toJSONString(t), XContentType.JSON);
        //客户端发送请求，获取相应的结果
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        //打印一下
        System.out.println(response.toString());
        System.out.println(response.status());
    }



    /**
     * 删除索引
     * @param indexName
     * @throws IOException
     */
    public void deleteIndex(String indexName) throws IOException{
        DeleteIndexRequest request = new DeleteIndexRequest(indexName);
        AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
        System.out.println("是否删除"+response);
    }





    @Autowired
    private JestHttpClient esClient;


        //searchContent是要查询的内容
        public void searchProduct(String searchContent) throws IOException {

            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//添加查询条件,QueryBuilders组合查询，这里我们可以和上面再kibana中查询语句对比一下
            searchSourceBuilder.query(QueryBuilders.boolQuery()
                    //匹配查询条件
                    .must(QueryBuilders.matchQuery("spu_name",searchContent))
                    .must(QueryBuilders.matchQuery("status",1)))
                    //分页查询，从第0条，查询20条数据
                    .from(0).size(20);

//建立查询
            Search search = new Search.Builder(searchSourceBuilder.toString())
                    //这里我们查询shop-trade索引（相当于数据库）
                    .addIndex("shop-trade")
                    .build();

//执行查询返回结果
            SearchResult searchResult = esClient.execute(search);
//将数据转成json格式
            String jsonString = searchResult.getJsonString();

            System.out.println(jsonString);
        }


    /**
     * 批量添加list 数据
     * @param tList  数据集合
     * @param <T>  数据泛型
     */
    public  <T> void addList(List<T> tList,String indexName){
        try {
            BulkRequest request = new BulkRequest();
            request.timeout("10s");
            //进行批处理请求
            for (int i = 0; i <tList.size() ; i++) {
                T t=tList.get(i);
                Object val=ReflectUtils.getObjectByFeild(t,ID);
                if(val==null){
                    continue;
                }
                String id=String.valueOf(val);
                request.add(
                        new IndexRequest(indexName)
                                .id(id)
                                .source(JSON.toJSONString(t),XContentType.JSON));
                System.out.println("添加id==>"+id);
            }
            BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
            System.out.println(response.hasFailures());
        }catch (IOException e){
            e.printStackTrace();
        }
    }


    /**
     * 根据id删除索引对应的id数据
     * @param indexName 索引名
     * @param idValue  要删除的id值
     * @throws IOException
     */
    public void deleteById(String indexName,String idValue) throws IOException{
        DeleteRequest request = new DeleteRequest(indexName, idValue);
        request.timeout("1s");
        DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
        System.out.println(response.status());
    }


    /**
     * 根据搜索数据
     * @param indexName 索引名称
     * @param field 字段属性
     * @param keyword 关键字
     * @param cls  反射
     * @param <T> 泛型
     * @return
     * @throws Exception
     */
    public <T> List<T>  searchList(String indexName,String field,String keyword,Class<T> cls) throws Exception{
        SearchRequest request = new SearchRequest(indexName);
        //构建搜索条件
        SearchSourceBuilder builder = new SearchSourceBuilder();

        //查询条件使用QueryBuilders工具来实现
        //QueryBuilders.termQuery 精准查询
        //QueryBuilders.matchAllQuery() 匹配全部
        MatchQueryBuilder matchQuery = QueryBuilders.matchQuery(field, keyword);
        builder.query(matchQuery);
        builder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        request.source(builder);

        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHit[] searchHits=response.getHits().getHits();
        List<T> tList=new ArrayList<>();
        for (int i = 0; i < searchHits.length; i++) {
            SearchHit hits=searchHits[i];
            Map<String, Object> map=hits.getSourceAsMap();
            T t= MapUtils.getObject(map,cls);
            tList.add(t);
        }
        return tList;
    }

    /**
     * 搜索构建器
     * @param indexName 索引名称
     * @param builder  构建器
     * @param cls  反射类
     * @param <T>  反射泛型
     * @return  数据对象
     * @throws Exception
     */
    public <T> Map<String, Object> searchListObject(String indexName,SearchSourceBuilder builder,Class<T> cls) throws Exception{
        SearchRequest request = new SearchRequest(indexName);
        builder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHit[] searchHits=response.getHits().getHits();
        Long toatl=response.getHits().getTotalHits().value;
        List<T> tList=new ArrayList<>();
        for (int i = 0; i < searchHits.length; i++) {
            SearchHit hits=searchHits[i];
            Map<String, Object> map=hits.getSourceAsMap();
            T t= MapUtils.getObject(map,cls);
            tList.add(t);
        }
        Map<String, Object> map=new HashMap<>();
        map.put("data",tList);
        map.put("total",toatl);
        return map;
    }




}
